home *** CD-ROM | disk | FTP | other *** search
- /*
-
- GUS.C
-
- Michael Chen
- mchen@cs.psu.edu
- 4/18/1993
-
- See the included .TXT file for terms and other information.
-
- Note that when playing back 16-bit samples, the start and end positions
- are measured in 16-bit words, not bytes!
-
- */
-
- #include "gus.h"
- #include <stdio.h>
- #include <dos.h>
-
- int GUSBase;
- int GUSMixer;
- int GUSStatus;
- int GUSTimerControl;
- int GUSTimerData;
- int GUSIRQDMAControl;
- int GUSMIDIControl;
- int GUSMIDIData;
- int GUSVoice;
- int GUSCommand;
- int GUSDataLo;
- int GUSDataHi;
- int GUSDRAMIO;
- int GUSCurrentVoice = -1;
- int GUSVoices = MINVOICES;
-
- byte GUSFreqDivisorTable[MAXVOICES+1] =
- /*
- Divisor table when setting voice frequency, based on number of voices.
- Remember, minimum of 14 active voices (though divisors given for 8 and up).
- */
- { -1, -1, -1, -1, -1, -1, -1, -1, 74, 66, 60, 54, 50, 46, 43, 40, 37,
- 35, 33, 31, 30, 28, 27, 26, 25, 24, 23, 22, 21, 20, 20, 19, 18 };
-
-
- void GUSDelay()
- /*
- Waits for GUS. (from Ultradox 2.0)
- */
- {
- int i;
-
- for (i=0; i<7; i++)
- inportb(0x300);
- }
-
- void GUSReset()
- /*
- Resets GUS. (from Ultradox 2.0)
- */
- {
- int i;
-
- /* Force routines to select voice explicitly first time */
- GUSCurrentVoice = -1;
-
- /* Put GUS in initialization mode */
- GUS_SetCommand(G_Initialize);
- outportb(GUSDataHi,0);
- GUSDelay();
- GUSDelay();
-
- /* Take GUS out of initialization mode */
- GUS_SetCommand(G_Initialize);
- outportb(GUSDataHi,1);
- GUSDelay();
- GUSDelay();
-
- /* Ramp voices to 0 --- doesn't work yet */
- /*
- GUSShutUp();
- */
-
- /* Clear DMA control */
- GUS_SetCommand(G_DMAControl);
- outportb(GUSDataHi,0);
-
- /* Clear timer control */
- GUS_SetCommand(G_TimerControl);
- outportb(GUSDataHi,0);
-
- /* Clear sample control */
- GUS_SetCommand(G_SampleControl);
- outportb(GUSDataHi,0);
-
- /* Set number of voices to minimum. */
- GUSSetVoices(MINVOICES);
-
- /* Clear pending DMA control */
- GUS_SetCommand(G_DMAControl);
- inportb(GUSDataHi);
-
- /* Clear pending timer control */
- GUS_SetCommand(G_TimerControl);
- inportb(GUSDataHi);
-
- /* Clear pending sample control */
- GUS_SetCommand(G_SampleControl);
- inportb(GUSDataHi);
-
- /* Reset voices */
- for (i=0; i<MAXVOICES; i++)
- {
- /* Select voice */
- GUSSelectVoice(i);
-
- /* Stop voice */
- GUSStopVoice(i);
-
- /* Turn off volume ramp */
- GUSStopRamp(i);
-
- /* Set to zero volume */
- GUSSetVolume(i,0);
-
- /* Set to center pan */
- GUSSetVoiceBalance(0,P_Center);
- }
-
- /* Clear pending DMA control */
- GUS_SetCommand(G_DMAControl);
- inportb(GUSDataHi);
-
- /* Clear pending sample control */
- GUS_SetCommand(G_SampleControl);
- inportb(GUSDataHi);
-
- /* Unknown read from IRQ status (?) */
- GUS_SetCommand(G_IRQStatus);
- inportb(GUSDataHi);
-
- /* Do something to initialization register (?) */
- GUS_SetCommand(G_Initialize);
- outportb(GUSDataHi,7);
-
- /* Set mixer to default (line-in and output on, mic-in off) */
- GUSSetMixer(M_OutputOn|M_LineInOn|M_MicInOff);
- }
-
- byte GUSPeek(longword addr)
- /*
- Peeks at value from GUS DRAM (long address).
- */
- {
- return GUS_Peek(addr >> 16,addr & 0xFFFF);
- }
-
- void GUSPoke(longword addr, byte val)
- /*
- Pokes value to GUS DRAM (long address).
- */
- {
- GUS_Poke(addr >> 16,addr & 0xFFFF,val);
- }
-
- byte GUSPokePeek(longword addr, byte val)
- /*
- Pokes value to GUS DRAM (long address), then immediately peeks same.
- */
- {
- return GUS_PokePeek(addr >> 16,addr & 0xFFFF,val);
- }
-
- static byte GUS_Peek(byte addrhi, word addrlo)
- /*
- Peeks at value from GUS DRAM.
- */
- {
- GUS_SetCommand(G_SetDRAMLo);
- outport(GUSDataLo,addrlo);
- GUS_SetCommand(G_SetDRAMHi);
- outportb(GUSDataHi,addrhi);
- return GUS_ReadDRAMIO();
- }
-
- static void GUS_Poke(byte addrhi, word addrlo, byte val)
- /*
- Pokes value to GUS DRAM.
- */
- {
- GUS_SetCommand(G_SetDRAMLo);
- outport(GUSDataLo,addrlo);
- GUS_SetCommand(G_SetDRAMHi);
- outportb(GUSDataHi,addrhi);
- GUS_SetDRAMIO(val);
- }
-
- static byte GUS_PokePeek(byte addrhi, word addrlo, byte val)
- /*
- Pokes value to GUS DRAM, then immediately peek from same location.
- */
- {
- GUS_SetCommand(G_SetDRAMLo);
- outport(GUSDataLo,addrlo);
- GUS_SetCommand(G_SetDRAMHi);
- outportb(GUSDataHi,addrhi);
- outportb(GUSDRAMIO,val);
- return GUS_ReadDRAMIO();
- }
-
- int ProbeGUS()
- /*
- Probes to see if GUS exists at current base address. (from Ultradox 2.0)
- */
- {
- byte testbyte = 0xAA;
- byte test1;
-
- GUS_SetCommand(G_Initialize);
- outportb(GUSDataHi,0);
- GUSDelay();
- GUSDelay();
- GUS_SetCommand(G_Initialize);
- outportb(GUSDataHi,1);
- GUSDelay();
- GUSDelay();
- GUSPoke(0,testbyte);
- GUSPoke(1,0xFF - testbyte);
- test1 = GUSPeek(0);
- GUS_SetCommand(G_Initialize);
- outportb(GUSDataHi,0);
- return (test1 == testbyte);
- }
-
- int DetectGUS()
- /*
- Returns base address of GUS ports, or 0 if no GUS detected.
- */
- {
- for (GUSBase = 0x210; (GUSBase < 0x270); GUSBase += 0x10)
- {
- GUSMixer = GUSBase;
- GUSStatus = GUSBase + 6;
- GUSTimerControl = GUSBase + 8;
- GUSTimerData = GUSBase + 9;
- GUSIRQDMAControl = GUSBase + 0xB;
- GUSMIDIControl = GUSBase + 0x100;
- GUSMIDIData = GUSBase + 0x101;
- GUSVoice = GUSBase + 0x102;
- GUSCommand = GUSBase + 0x103;
- GUSDataLo = GUSBase + 0x104;
- GUSDataHi = GUSBase + 0x105;
- GUSDRAMIO = GUSBase + 0x107;
- if (ProbeGUS()) break;
- }
- if (GUSBase < 0x270)
- return GUSBase;
- else
- return 0;
- }
-
- static void GUS_SelectVoice(byte voice)
- /*
- Selects current GUS voice for subsequent commands.
- */
- {
- GUS_SetVoice(voice);
- GUSCurrentVoice = voice;
- }
-
- void GUSSelectVoice(byte voice)
- /*
- Changes current GUS voice for subsequent commands if necessary.
- */
- {
- if (GUSCurrentVoice != voice)
- GUS_SelectVoice(voice);
- }
-
- void GUSStopVoice(byte voice)
- /*
- Stops GUS voice.
- */
- {
- byte b;
-
- GUSSelectVoice(voice);
- b = GUSReadVoiceMode(voice);
- if (!(b & V_VoiceStopped))
- {
- b |= 3;
- GUS_SetCommand(G_SetVoiceMode);
- outportb(GUSDataHi,b);
- }
- }
-
- void GUSStartVoice(byte voice)
- /*
- Starts GUS voice.
- */
- {
- byte b;
-
- GUSSelectVoice(voice);
- b = GUSReadVoiceMode(voice);
- if (b & V_VoiceStopped)
- {
- b &= 0xFC;
- GUS_SetCommand(G_SetVoiceMode);
- outportb(GUSDataHi,b);
- }
- }
-
- void GUSSetVoiceMode(byte voice, byte mode)
- /*
- Sets GUS voice mode (not start/stop, though) directly.
- */
- {
- byte b;
-
- GUSSelectVoice(voice);
- GUS_SetCommand(G_ReadVoiceMode);
- b = inportb(GUSDataHi);
- b &= 3;
- b |= (mode & 0xFC);
- GUS_SetCommand(G_SetVoiceMode);
- outportb(GUSDataHi,b);
- }
-
- void GUSSetVoices(byte voices)
- /*
- Sets number of voices for GUS.
- */
- {
- GUS_SetCommand(G_SetMaxVoice);
- outportb(GUSDataHi,((voices-1) | G_VoiceMask));
- GUSVoices = voices;
- }
-
- void GUSSetVoiceFreq(byte voice, word freq)
- /*
- Sets GUS voice frequency, taking into account number of voices.
- */
- {
- GUSSelectVoice(voice);
- GUS_SetCommand(G_SetVoiceFreq);
- outport(GUSDataLo,freq/GUSFreqDivisorTable[GUSVoices]);
- }
-
- static void GUS_SetLoopStart(byte voice, word hi, word lo)
- {
- GUSSelectVoice(voice);
- GUS_SetCommand(G_SetLoopStartLo);
- outport(GUSDataLo,lo);
- GUS_SetCommand(G_SetLoopStartHi);
- outport(GUSDataLo,hi);
- }
-
- static void GUS_SetLoopEnd(byte voice, word hi, word lo)
- {
- GUSSelectVoice(voice);
- GUS_SetCommand(G_SetLoopEndLo);
- outport(GUSDataLo,lo);
- GUS_SetCommand(G_SetLoopEndHi);
- outport(GUSDataLo,hi);
- }
-
- static void GUS_SetPosition(byte voice, word hi, word lo)
- {
- GUSSelectVoice(voice);
- GUS_SetCommand(G_SetPositionLo);
- outport(GUSDataLo,lo);
- GUS_SetCommand(G_SetPositionHi);
- outport(GUSDataLo,hi);
- }
-
- void GUSSetLoopStart(byte voice, longword addr)
- /*
- Sets loop start of voice.
- */
- {
- GUS_SetLoopStart(voice,addr << 9, addr >> 7);
- }
-
- void GUSSetLoopEnd(byte voice, longword addr)
- /*
- Sets loop (sample) end of voice.
- */
- {
- GUS_SetLoopEnd(voice,addr << 9, addr >> 7);
- }
-
- void GUSSetPosition(byte voice, longword addr)
- /*
- Sets position (sample begin) of voice.
- */
- {
- GUS_SetPosition(voice,addr << 9, addr >> 7);
- }
-
- longword GUSReadLoopEnd(byte voice)
- /*
- Reads loop (sample) end of voice.
- */
- {
- longword l;
-
- GUSSelectVoice(voice);
- GUS_SetCommand(G_ReadLoopEndLo);
- l = ((longword)((word)inport(GUSDataLo)) & 0x1FFF) << 7;
- GUS_SetCommand(G_ReadLoopEndHi);
- l |= ((word)inport(GUSDataLo)) >> 9;
- return l;
- }
-
- longword GUSReadLoopStart(byte voice)
- /*
- Reads loop start of voice.
- */
- {
- longword l;
-
- GUSSelectVoice(voice);
- GUS_SetCommand(G_ReadLoopStartLo);
- l = ((longword)((word)inport(GUSDataLo)) & 0x1FFF) << 7;
- GUS_SetCommand(G_ReadLoopStartHi);
- l |= ((word)inport(GUSDataLo)) >> 9;
- return l;
- }
-
- longword GUSReadPosition(byte voice)
- /*
- Reads position (sample begin) of voice.
- */
- {
- longword l;
-
- GUSSelectVoice(voice);
- GUS_SetCommand(G_ReadPositionLo);
- l = ((longword)((word)inport(GUSDataLo)) & 0x1FFF) << 7;
- GUS_SetCommand(G_ReadPositionHi);
- l |= ((word)inport(GUSDataLo)) >> 9;
- return l;
- }
-
- byte GUSReadVoiceMode(byte voice)
- /*
- Reads mode of voice.
- */
- {
- GUSSelectVoice(voice);
- GUS_SetCommand(G_ReadVoiceMode);
- return inportb(GUSDataHi);
- }
-
- word GUSReadVoiceFreq(byte voice)
- /*
- Reads frequency of voice.
- */
- {
- GUSSelectVoice(voice);
- GUS_SetCommand(G_ReadVoiceFreq);
- return inport(GUSDataLo) * GUSFreqDivisorTable[GUSVoices];
- }
-
- void GUSSetVolume(byte voice, word vol)
- /*
- Sets volume of voice.
- */
- {
- GUSSelectVoice(voice);
- GUS_SetCommand(G_SetVolume);
- outport(GUSDataLo,vol);
- }
-
- word GUSReadVolume(byte voice)
- /*
- Reads volume of voice.
- */
- {
- GUSSelectVoice(voice);
- GUS_SetCommand(G_ReadVolume);
- return (word)inport(GUSDataLo);
- }
-
- void GUSSetVoiceBalance(byte voice, byte pan)
- /*
- Sets pan of voice.
- */
- {
- GUSSelectVoice(voice);
- GUS_SetCommand(G_SetVoiceBalance);
- outportb(GUSDataHi,pan);
- }
-
- byte GUSReadVoiceBalance(byte voice)
- /*
- Reads pan of voice.
- */
- {
- GUSSelectVoice(voice);
- GUS_SetCommand(G_ReadVoiceBalance);
- return inportb(GUSDataHi);
- }
-
- /*
-
- void GUSSetDRAM(longword addr, void* buf, longword len)
-
- Set region of GUS DRAM starting at addr, len bytes long to buf.
- Not yet optimized for speed.
-
- {
- byte* bp;
-
- bp = buf;
- while (len-- > 0)
- {
- GUSPoke(addr++,*bp++);
- }
- }
-
- */
-
- void GUSSetDRAM(longword addr, void* buf, longword len)
- /*
- Set region of GUS DRAM starting at addr, len bytes long to buf.
- (Supposedly) partially optimized for speed.
- */
- {
- byte* bp;
- byte addrhi;
- word addrlo;
-
- bp = buf;
- addrhi = addr >> 16;
- addrlo = addr & 0xFFFF;
-
- GUS_SetCommand(G_SetDRAMHi);
- outportb(GUSDataHi,addrhi);
- GUS_SetCommand(G_SetDRAMLo);
-
- while (len-- > 0)
- {
- outport(GUSDataLo,addrlo++);
- GUS_SetDRAMIO(*bp++);
- if (!addrlo)
- {
- GUS_SetCommand(G_SetDRAMHi);
- outportb(GUSDataHi,addrhi);
- GUS_SetCommand(G_SetDRAMLo);
- }
- }
- }
-
- /*
-
- void GUSReadDRAM(longword addr, void* buf, longword len)
-
- Read region of GUS DRAM starting at addr, len bytes long to buf.
- Not yet optimized for speed.
-
- {
- byte* bp;
-
- bp = buf;
- while (len-- > 0)
- {
- *bp++ = GUSPeek(addr++);
- }
- }
-
- */
-
- void GUSReadDRAM(longword addr, void* buf, longword len)
- /*
- Read region of GUS DRAM starting at addr, len bytes long to buf.
- (Supposedly) partially optimized for speed.
- */
- {
- byte* bp;
- byte addrhi;
- word addrlo;
-
- bp = buf;
- addrhi = addr >> 16;
- addrlo = addr & 0xFFFF;
-
- GUS_SetCommand(G_SetDRAMHi);
- outportb(GUSDataHi,addrhi);
- GUS_SetCommand(G_SetDRAMLo);
-
- while (len-- > 0)
- {
- outport(GUSDataLo,addrlo++);
- *bp++ = GUS_ReadDRAMIO();
- if (!addrlo)
- {
- GUS_SetCommand(G_SetDRAMHi);
- outportb(GUSDataHi,addrhi);
- GUS_SetCommand(G_SetDRAMLo);
- }
- }
- }
-
- void GUSFillDRAM(longword addr, byte b, longword len)
- /*
- Set region of GUS DRAM starting at addr, len bytes long to b.
- (Supposedly) partially optimized for speed.
- */
- {
- byte addrhi;
- word addrlo;
-
- addrhi = addr >> 16;
- addrlo = addr & 0xFFFF;
-
- GUS_SetCommand(G_SetDRAMHi);
- outportb(GUSDataHi,addrhi);
- GUS_SetCommand(G_SetDRAMLo);
-
- while (len-- > 0)
- {
- outport(GUSDataLo,addrlo++);
- GUS_SetDRAMIO(b);
- if (!addrlo)
- {
- GUS_SetCommand(G_SetDRAMHi);
- outportb(GUSDataHi,addrhi);
- GUS_SetCommand(G_SetDRAMLo);
- }
- }
- }
-
- void GUSSetVolumeRampRate(byte voice, byte incr, byte scale)
- /*
- Set voice's volume ramp rate. Scale updates as follows:
- 00 - every access
- 01 - every 8th access
- 10 - every 64th access
- 11 - every 512th access
- Advice from Ultradox 2.0: use increments of 8 or less; don't ramp to either
- extreme (below 636, above 4032)
- */
- {
- GUSSelectVoice(voice);
- GUS_SetCommand(G_SetVolumeRampRate);
- outportb(GUSDataHi,(incr & 0x3f) | ((scale & 3) << 6));
- }
-
- byte GUSReadVolumeRampRate(byte voice)
- {
- GUSSelectVoice(voice);
- GUS_SetCommand(G_SetVolumeRampRate);
- return inportb(GUSDataHi);
- }
-
- void GUSSetVolumeRampStart(byte voice, word vol)
- {
- GUSSelectVoice(voice);
- GUS_SetCommand(G_SetVolumeRampStart);
- outportb(GUSDataHi,(vol >> 8));
- }
-
- void GUSSetVolumeRampEnd(byte voice, word vol)
- {
- GUSSelectVoice(voice);
- GUS_SetCommand(G_SetVolumeRampEnd);
- outportb(GUSDataHi,(vol >> 8));
- }
-
- word GUSReadVolumeRampStart(byte voice)
- {
- GUSSelectVoice(voice);
- GUS_SetCommand(G_ReadVolumeRampStart);
- return ((word)inportb(GUSDataHi)) << 8;
- }
-
- word GUSReadVolumeRampEnd(byte voice)
- {
- GUSSelectVoice(voice);
- GUS_SetCommand(G_ReadVolumeRampEnd);
- return ((word)inportb(GUSDataHi)) << 8;
- }
-
- void GUSSetVolumeControl(byte voice, byte mode)
- {
- GUSSelectVoice(voice);
- GUS_SetCommand(G_SetVolumeControl);
- outportb(GUSDataHi,mode);
- }
-
- byte GUSReadVolumeControl(byte voice)
- {
- GUSSelectVoice(voice);
- GUS_SetCommand(G_ReadVolumeControl);
- return inportb(GUSDataHi);
- }
-
- static int GUSMixerState = 0;
-
- void GUSSetMixer(byte mode)
- {
- GUSMixerState = mode;
- GUS_SetMixer(mode);
- }
-
- byte GUSReadMixer()
- {
- return GUSMixerState;
- }
-
- void GUSStopRamp(byte voice)
- /*
- Stops GUS voice ramp.
- */
- {
- byte b;
-
- GUSSelectVoice(voice);
- b = GUSReadVolumeControl(voice);
- if (!(b & V_RampStopped))
- {
- b |= 3;
- GUS_SetCommand(G_SetVolumeControl);
- outportb(GUSDataHi,b);
- }
- }
-
- void GUSStartRamp(byte voice)
- /*
- Starts GUS voice ramp.
- */
- {
- byte b;
-
- GUSSelectVoice(voice);
- b = GUSReadVolumeControl(voice);
- if (b & V_RampStopped)
- {
- b &= 0xFC;
- GUS_SetCommand(G_SetVolumeControl);
- outportb(GUSDataHi,b);
- }
- }
-
- void GUSShutUp()
- {
- int i;
- word vol;
- byte incr;
-
- for (i = 0; i < MAXVOICES; i++)
- {
- GUSSelectVoice(i);
- vol = GUSReadVolume(i);
- if (vol > 0)
- {
- GUSSetVolumeRampStart(i,vol);
- GUSSetVolumeRampEnd(i,0);
- GUSSetVolumeRampRate(i,1,R_Every1);
- GUSSetVolumeControl(i,V_StartRamp|V_Decreasing);
- GUSStartRamp(i);
-
- /* code for ramps seems not to work; no change in volume */
- while ((incr = GUSReadVolumeControl(i) & V_RampStopped)
- != V_RampStopped)
- {
- vol = GUSReadVolume(i);
- if (vol >> 12 == 0) break; /* quiet enough */
- printf("vol 0x%04x mode 0x%02x\r",vol,incr);
- }
- }
- }
- }
-
-